import React, {
  forwardRef,
  useEffect,
  useState,
  useRef,
  useImperativeHandle,
} from "react";
import PropTypes from "prop-types";
import BScroll from "@better-scroll/core";
import PullDown from "@better-scroll/pull-down";
import Pullup from "@better-scroll/pull-up";
import { ScrollContent } from "./style";

// 使用下拉加载的插件
BScroll.use(PullDown);
BScroll.use(Pullup);

// 函数式组件天生不具备被上层组件直接调用 ref 的条件，因此需要用 React 当中一些特殊的方式来处理，即使用 forwardRef 进行包裹。
const Scroll = forwardRef((props, ref) => {
  const {
    pullDown = () => console.log("下拉刷新"),
    pullUp = () => console.log("上拉加载"),
  } = props;

  const [bScroll, setBScroll] = useState(null);
  const wrapperRef = useRef();

  // 初始化BScroll
  useEffect(() => {
    const bs = new BScroll(wrapperRef.current, {
      probeType: 3,
      click: true,
      bounceTime: 800,
      pullDownRefresh: {
        threshold: 90, // 下拉所需要触发的阈值
        stop: 0, //下拉之后的回弹位置
      },
      pullUpLoad: {
        threshold: 90,
      },
    });
    setBScroll(bs);
    return () => bs.destroy();
  }, []);

  // 页面每次刷新都需要重新计算容器高度
  useEffect(() => {
    if (bScroll) {
      bScroll.refresh();
    }
  });

  // 上拉加载事件
  useEffect(() => {
    if (!bScroll) return;
    bScroll.on("pullingUp", () => {
      pullUp?.();
      bScroll.finishPullUp();
      bScroll.refresh();
    });
    return () => bScroll.destroy();
  }, [bScroll, pullUp]);

  // 下拉刷新事件
  useEffect(() => {
    if (!bScroll) return;
    bScroll.on("pullingDown", () => {
      pullDown?.();
      bScroll.finishPullDown();
      bScroll.refresh();
    });
    return () => bScroll.destroy();
  }, [bScroll, pullDown]);

  // 暴露给外界方法，ref是forwardRef的参数，在函数组件的第二个参数中已经传入
  useImperativeHandle(ref, () => ({
    // 重新计算DOM高度
    refresh() {
      if (bScroll) {
        bScroll.refresh();
      }
    },
    // 获取BScroll的实例
    getBScroll() {
      if (bScroll) {
        return bScroll;
      }
    },
  }));

  return <ScrollContent ref={wrapperRef}>{props.children}</ScrollContent>;
});

Scroll.propTypes = {
  pullDown: PropTypes.func, // 下拉刷新的处理函数
  pullUp: PropTypes.func, // 上拉加载的处理函数
};

export default Scroll;
